package aryn.framework.display;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Insets;

import aryn.framework.display.drawable.Drawable;
import aryn.framework.utilities.Util;

public class ButtonBorder extends Drawable implements Cloneable {

	public ButtonBorder(int x, int y, int width, int height, MyCanvas canvas) {
		super(x, y, Priority.FOREGROUND, canvas);
		this.width = width;
		this.height = height;
		setBorderThickness(2);
		setType(THREED_OUT);
		setMargins(3);
	}
	
	public ButtonBorder(int x, int y, int width, int height, MyCanvas canvas, boolean isPressed) {
		this(x, y, width, height, canvas);
		setBorderThickness(2);
		if (isPressed) {
			setType(THREED_IN);
			setMargins(4, 4, 2, 2);
		} else {
			setType(THREED_OUT);
			setMargins(3);
		}
	}

	public static final int NONE = 0;
	public static final int LINE = 1;
	public static final int THREED_IN = 2;
	public static final int THREED_OUT = 3;
	public static final int ETCHED_IN = 4;
	public static final int EMBOSSED_OUT = 5;
	public static final int ROUND_RECT = 6;

	private int type = NONE;
	private Color border = Color.GRAY;
	private int topMargin = 0;
	private int leftMargin = 0;
	private int bottomMargin = 0;
	private int rightMargin = 0;
	private int minMargin = 0;
	private int maxMargin = 0;
	private int borderThickness = 0;
	private int width;
	private int height;

	private static final double BRIGHTER_FACTOR = 0.8;
	private static final double DARKER_FACTOR = 0.65;

	public static Color brighter(Color color) {
		Color newcolor = new Color(Math.min(
				(int) (color.getRed() * (1 / BRIGHTER_FACTOR)), 255), Math.min(
				(int) (color.getGreen() * (1 / BRIGHTER_FACTOR)), 255),
				Math.min((int) (color.getBlue() * (1 / BRIGHTER_FACTOR)), 255));
		if (newcolor.equals(color)) {
			return Color.white;
		}
		return newcolor;
	}

	public static Color darker(Color color) {
		Color newcolor = new Color(Math.max(
				(int) (color.getRed() * DARKER_FACTOR), 0), Math.max(
				(int) (color.getGreen() * DARKER_FACTOR), 0), Math.max(
				(int) (color.getBlue() * DARKER_FACTOR), 0));
		if (newcolor.equals(color)) {
			return Color.black;
		}
		return newcolor;
	}

	public Object clone() {
		ButtonBorder newborder = new ButtonBorder(this.x, this.y, this.width,
				this.height, canvas);
		newborder.type = type;
		newborder.border = border;
		newborder.topMargin = topMargin;
		newborder.leftMargin = leftMargin;
		newborder.bottomMargin = bottomMargin;
		newborder.rightMargin = rightMargin;
		newborder.minMargin = minMargin;
		newborder.maxMargin = maxMargin;
		newborder.borderThickness = borderThickness;
		return newborder;
	}

	public void setNoInsets() {
		topMargin = 0;
		leftMargin = 0;
		bottomMargin = 0;
		rightMargin = 0;
		minMargin = 0;
		maxMargin = 0;
		borderThickness = 0;
	}

	public int getType() {
		return type;
	}

	public synchronized void setType(int type) {
		this.type = type;
	}

	public Color getBorder() {
		return border;
	}

	public synchronized void setBorder(Color border) {
		this.border = border;
	}

	public int getTopMargin() {
		return topMargin;
	}

	public int getLeftMargin() {
		return leftMargin;
	}

	public int getBottomMargin() {
		return bottomMargin;
	}

	public int getRightMargin() {
		return rightMargin;
	}

	private void resetMinMaxMargin() {
		maxMargin = topMargin;
		maxMargin = Math.max(maxMargin, leftMargin);
		maxMargin = Math.max(maxMargin, bottomMargin);
		maxMargin = Math.max(maxMargin, rightMargin);
		minMargin = topMargin;
		minMargin = Math.min(minMargin, leftMargin);
		minMargin = Math.min(minMargin, bottomMargin);
		minMargin = Math.min(minMargin, rightMargin);
	}

	public synchronized void setMargins(int margin) {
		topMargin = margin;
		leftMargin = margin;
		bottomMargin = margin;
		rightMargin = margin;
		resetMinMaxMargin();
	}

	public synchronized void setMargins(int top, int left, int bottom, int right) {
		topMargin = top;
		leftMargin = left;
		bottomMargin = bottom;
		rightMargin = right;
		resetMinMaxMargin();
	}

	public synchronized void setTopMargin(int margin) {
		topMargin = margin;
		resetMinMaxMargin();
	}

	public synchronized void setLeftMargin(int margin) {
		leftMargin = margin;
		resetMinMaxMargin();
	}

	public synchronized void setBottomMargin(int margin) {
		bottomMargin = margin;
		resetMinMaxMargin();
	}

	public synchronized void setRightMargin(int margin) {
		rightMargin = margin;
		resetMinMaxMargin();
	}

	public int getBorderThickness() {
		return borderThickness;
	}

	public synchronized void setBorderThickness(int borderThickness) {
		this.borderThickness = borderThickness;
	}

	public Insets getInsets() {
		int top = borderThickness + topMargin;
		int left = borderThickness + leftMargin;
		int bottom = borderThickness + bottomMargin;
		int right = borderThickness + rightMargin;
		return new Insets(top, left, bottom, right);
	}

	public void draw(Graphics g) {
		g.setColor(border);

		Color brighter = null;
		Color darker = null;

		switch (type) {

		case THREED_IN:
		case THREED_OUT:
		case ETCHED_IN:
		case EMBOSSED_OUT: {
			brighter = brighter(border);
			darker = darker(border);
			break;
		}
		}

		for (int idx = 0; idx < borderThickness; idx++) {
			if (type == LINE) {
				g.drawRect(x + idx, y + idx, ((width - 1) - (idx * 2)),
						((height - 1) - (idx * 2)));
			} else if (type == ROUND_RECT) {

				int arcSize = (minMargin * 8 - (idx * 2));
				int rrx = x + idx;
				int rry = y + idx;
				int rrw = (width - 1) - (idx * 2);
				int rrh = (height - 1) - (idx * 2);

				g.drawRoundRect(x + idx, y + idx, rrw, rrh, arcSize, arcSize);
				if ((idx + 1) < borderThickness) {
					g.drawRoundRect(rrx, rry, rrw, rrh - 1, arcSize - 1,
							arcSize);
					g.drawRoundRect(rrx + 1, rry, rrw, rrh - 1, arcSize - 1,
							arcSize);
					g.drawRoundRect(rrx, rry, rrw - 1, rrh, arcSize,
							arcSize - 1);
					g.drawRoundRect(rrx, rry + 1, rrw - 1, rrh, arcSize,
							arcSize - 1);
				}
			} else {
				Color top = brighter;
				Color bottom = darker;

				if ((type == THREED_IN) || (type == ETCHED_IN)) {
					top = darker;
					bottom = brighter;
				}

				if ((type == ETCHED_IN) || (type == EMBOSSED_OUT)) {
					if (idx >= (borderThickness / 2)) {
						Color temp = top;
						top = bottom;
						bottom = temp;
					}

				}

				if ((idx == (borderThickness - 1)) && (type == THREED_IN)) {
					g.setColor(darker(top));
				} else {
					g.setColor(top);
				}

				g.drawLine(x + idx, y + idx, x + idx, y
						+ ((height - 1) - (idx)));
				g.drawLine(x + idx, y + idx, x + ((width - 1) - (idx)), y + idx);

				if (((idx == (borderThickness - 1)) && (type == THREED_IN))
						|| ((idx == 0) && (type == THREED_OUT))) {
					g.setColor(darker(bottom));
				} else {
					g.setColor(bottom);
				}

				g.drawLine(x + idx, y + ((height - 1) - (idx)), x
						+ ((width - 1) - (idx)), y + ((height - 1) - (idx)));
				g.drawLine(x + ((width - 1) - (idx)), y + idx, x
						+ ((width - 1) - (idx)), y + ((height - 1) - (idx)));
			}
		}

	}

	@Override
	public boolean isMouseOver(int mouseX, int mouseY) {
		Insets brd = getInsets();
		return Util.mouseBound(mouseX, mouseY,
				this.x - brd.left, this.y - brd.top,
				this.x + this.width + brd.right, this.y	+ this.height + brd.bottom);
	}
}